home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 / Ham Radio 2000.iso / ham2000 / packet / monax25 / serialip.asm < prev    next >
Assembly Source File  |  1987-06-04  |  14KB  |  520 lines

  1.     page    60,132
  2.     title    SERIAL     C interrupt driven serial I/O routines for IBM PC COM ports
  3.  
  4. ;These routines allow c programs to use serial port 0 in an interrupt
  5. ;driven environment. This environment is locally generated and controlled
  6. ;
  7. ;This program is released to the public domain for non-commercial
  8. ;uses. Please do not charge "copying fees" when redistrubiting
  9. ;this program. Feedback is desired.
  10. ;
  11. ;Skip Hansen, WB6YMH 6/22/86
  12. ;RCP/M (213) 541-2503
  13. ;or via RLI linked systems at WB6KAJ or KD6SQ
  14. ;
  15. ;    1/84    Greg Lindberg    Original routines written for Pronto Computer
  16. ;
  17. ;    2/86    Skip,WB6YMH    Modified for use on IBM PC COM1
  18. ;
  19. ;    4/26/86 Lee, WB6KAJ    Modified transmit byte routine to check
  20. ;                CTS before sending a byte for use with
  21. ;                hardware flow control.
  22. ;
  23. ;    01/30/87 Mike, WA6FXT    Modified to conform to Microsoft 'C' 4.0
  24. ;                Also added DTR control to _serinit, _serldone
  25. ;
  26. ;    01/31/87 Mike, WA6FXT    Modified to allow COM port selection to be
  27. ;                done dynamic (command option).
  28. ;
  29. ;    6/1/87    Skip, WB6YMH    Corrected bug in serldone. Fixed bug in
  30. ;                serlbaud caused by fallthru logic after
  31. ;                port option was added to serlinit.
  32. ;
  33. ;
  34.  
  35. ;
  36. ;macro for output from al to 16 bit port adr
  37. ;
  38. outbyte        macro    name
  39.         mov    dx,name     ;point dx to port adr
  40.         out    dx,al        ;output 8 bit value
  41.         endm
  42. ;
  43. ;macro for byte input to al from 16 bit port
  44. ;
  45. inbyte        macro    name
  46.         mov    dx,name     ;point dx to port adr
  47.         in    al,dx        ;read byte
  48.         endm
  49.  
  50. ;
  51. ;macro for output from al to 16 bit port base adr with offset 'name'
  52. ;
  53. outport        macro    name
  54.         mov    dx,name        ;get the offset value
  55.         call    out_byte    ;output the byte
  56.         endm
  57. ;
  58. ;macro for byte input to al from 16 bit port base adr with offset 'name'
  59. ;
  60. inport        macro    name
  61.         mov    ax,port_base    ;get the base address
  62.         add    ax,name        ;add the OFFSET
  63.         mov    dx,ax        ;set DX to point at port address
  64.         in    al,dx        ;read byte
  65.         endm
  66.  
  67. false        equ    0
  68. true        equ    not false
  69.  
  70. i8259_mask    equ    21h        ;interrupt mask register
  71. i8259_ctrl    equ    20h        ;interrupt controller control port
  72. rdaien        equ    1        ;enable bit for RDA interrupts
  73. linmod        equ    03h        ;line mode, 8 bits, no parity
  74. mdmmod        equ    0bh        ;modem mode= DTR and RTS high &
  75.  
  76. ;    COM port definitions
  77. COM1        equ    3f8h        ;base address of COM1 8250
  78. com_vec1     equ    0ch        ;interrupt vector for COM1
  79. int_level1    equ    4        ;interrupt level on 8259
  80. int_mask1    equ    00010000b    ;interrupt mask bit in 8259
  81.  
  82. COM2        equ    2f8h        ;base address of COM2 8250
  83. com_vec2     equ    0bh        ;interrupt vector for COM2
  84. int_level2    equ    3        ;interrupt level on 8259
  85. int_mask2    equ    00001000b    ;interrupt mask bit in 8259
  86.  
  87. ;    OFFSETS from base address of COM port
  88. mdmdat        equ    0        ;offset to data port
  89. mdmint        equ    1        ;interrupt enable register
  90. mdmlin        equ    3        ;line control register
  91. mdmmdm        equ    4        ;modem control register
  92. mdmsta        equ    5        ;line status register
  93. mdmmsr        equ    6        ;modem status register
  94.  
  95. DTR_BIT     equ    1        ;DTR control bit in modem control reg
  96. RTS_BIT     equ    2        ;RTS control bit
  97.  
  98. check_cts    equ    true
  99.  
  100. _TEXT    SEGMENT    BYTE    PUBLIC    'CODE'
  101. _TEXT    ENDS
  102. _DATA    SEGMENT    WORD    PUBLIC    'DATA'
  103. _DATA    ENDS
  104. CONST    SEGMENT    WORD    PUBLIC    'CONST'
  105. CONST    ENDS
  106. _BBS    SEGMENT    WORD    PUBLIC    'BBS'
  107. _BBS    ENDS
  108.  
  109. DGROUP    GROUP    CONST,    _BBS,    _DATA
  110.  
  111.     ASSUME    CS:_TEXT, DS:DGROUP, SS:DGROUP
  112.  
  113. _DATA    SEGMENT
  114.  
  115.     public    trnbuffin,trnbuffout,trn_buff,trn_buff_end
  116.     public    rcvbuffin,rcvbuffout,rcv_buff,rcv_buff_end
  117.     public    com_port,port_base
  118.  
  119. ;    DATA AREA
  120. trnbuffin    dw    offset DGROUP:trn_buff    ;pointer to input point in transmit buffer
  121. trnbuffout    dw    offset DGROUP:trn_buff    ;pointer to output point in transmit buffer
  122. trn_buff    db    160 dup (?)    ;transmit buffer
  123. trn_buff_end    equ    $
  124. rcvbuffin    dw    offset DGROUP:rcv_buff    ;pointer to input point in receive buffer
  125. rcvbuffout    dw    offset DGROUP:rcv_buff    ;pointer to output point in receive buffer
  126. rcv_buff    dw    2048 dup (?)    ;receive buffer
  127. rcv_buff_end    equ    $
  128.         dw    100 dup (?)    ;local interrupt stack
  129. intstk        equ    $
  130. ssseg        dw    ?        ;storage for interrupted stack seg
  131. spptr        dw    ?        ;storage for interrupted stack pointer
  132. com_port    dw    ?        ;storage for COM port selection
  133. port_base    dw    ?        ;storage for COM port base address
  134.  
  135. _DATA    ENDS
  136.  
  137.  
  138. _TEXT    SEGMENT
  139.  
  140.     PUBLIC    _SERLINIT,_TRNBYTE,_RCVBYTE,_SERLDONE
  141.     PUBLIC    _TIMERCV,_PURGERCV,_SERLBAUD,_rcvint
  142.     PUBLIC    _dtr_on,_dtr_off,rts_on,rts_off
  143.  
  144. dsseg        dw    $        ;storage for C data segment
  145.  
  146. ;
  147. ; name        serlbaud -- baud rate initialazation for serial port 0
  148. ;
  149. ; synopsis    serlbaud(,port_num,baud);
  150. ;        int port_num;    port number (IE: 0=COM1)
  151. ;        int baud;    baud rate for serial port
  152. ;
  153. ; description    This routine initializes serial port 0 at the specified
  154. ;        baud rate.
  155. ;
  156. _serlbaud    proc    near
  157.         push    bp        ;save BP
  158.         mov    bp,sp        ;point to passed parms
  159.         mov    dx,[bp+4]    ;get port number
  160.         mov    al,[bp+6]    ;get requested baud rate
  161.         ror    al,1        ;put in right place
  162.         ror    al,1
  163.         ror    al,1
  164.         and    al,0e0h     ;save only baud rate
  165.         or    al,3        ;get rest of int 14h command
  166.         xor    ah,ah        ;make it init command
  167.         int    14h        ;init port 0 for 8 data bits, 1 stop, no parity
  168.         mov    ax,[bp+4]    ;get port number
  169.         push    ax        ;
  170.         call    _serlinit    ;
  171.         pop    ax        ;fix stack
  172.         pop    bp        ;restore callers BP
  173.         ret            ;all done so fall thru to serlinit()
  174.                     ;since ibm clears interrupt setup with
  175.                     ;int 14 baudrate calls
  176. _serlbaud    endp
  177.  
  178. ;
  179. ; name        serlinit -- interrupt driven serial initialization
  180. ;
  181. ; synopsis    serlinit(port_num);
  182. ;        int port_num;    port number (IE: 0=COM1)
  183. ;
  184. ; description    This routine initializes interrupts for serial port 0.
  185. ;
  186. _serlinit    proc    near
  187.         push    bp        ;save BP
  188.         mov    bp,sp        ;point to passed parms
  189.         push    ds        ;save data segment
  190.         mov    dsseg,ds    ;save C data segment for interrupt routine
  191.  
  192.         mov    ax,[bp+4]    ;get the port number
  193.         mov    com_port,ax    ;set the number for later use
  194.         mov    dx,COM1        ;assume COM1
  195.         cmp    ax,0        ;see if COM1
  196.         jz    ser_setcom
  197.         mov    dx,COM2        ;set for COM2
  198. ser_setcom:    mov    port_base,dx    ;set the port base address
  199.  
  200.         mov    ax,com_port    ;get the port number
  201.         mov    bx,2500h+com_vec1    ;assume COM1
  202.         cmp    ax,0        ;COM1?
  203.         jz    ser_setvec ;yes
  204.         mov    bx,2500h+com_vec2    ;must be COM2
  205.  
  206. ser_setvec:    mov    ax,cs        ;set up for init of interrupt vector
  207.         mov    ds,ax
  208.         mov    dx,offset cs:_rcvint    ;point to isr
  209.         mov    ax,bx        ;move the vector to AX
  210.  
  211.         cli            ;no interrupts now
  212.         int    21h        ;initialize receive interrupt
  213.         pop    ds        ;restore data pointer
  214.         mov    ax,offset ds:trn_buff ;clear transmit buffer
  215.         mov    trnbuffin,ax
  216.         mov    trnbuffout,ax
  217.         mov    ax,offset ds:rcv_buff ;clear receive buffer
  218.         mov    rcvbuffin,ax
  219.         mov    rcvbuffout,ax
  220.         inport    mdmdat        ;clear any garbarge characters
  221.         in    al,dx        ;from COM port
  222.         in    al,dx        ;
  223.         mov    al,linmod    ;clear DLAB bit and set line mode
  224.         outport    mdmlin        ;
  225.         mov    al,mdmmod    ;get mode to use
  226.         outport    mdmmdm        ;to modem control register
  227.         mov    al,rdaien    ;enable interrupts from RDA
  228.         outport    mdmint        ;
  229.         mov    dx,i8259_mask    ;unmask interrupts from serial port 0
  230.         in    al,dx        ;get present mask
  231.  
  232.         push    ax        ;save it
  233.         mov    ax,com_port    ; check the port
  234.         cmp    ax,0        ;see if COM1
  235.         jnz     ser_mask2    ;must be COM2
  236.  
  237.         pop    ax        ;restore AX
  238.         and    al,not int_mask1 ;enable interrupts for COM1
  239.         jmp    short ser_setmask
  240.  
  241. ser_mask2:    pop    ax        ;restore AX
  242.         and    al,not int_mask2 ;enable interrupts for COM2
  243.  
  244. ser_setmask:    out    dx,al        ;restore new mask
  245.  
  246.         call    _dtr_on        ;allow inputs
  247.  
  248.         sti            ;interrupts back on
  249.         pop    bp        ;restore callers BP
  250.         ret            ;all done so exit
  251. _serlinit    endp
  252.  
  253. ;
  254. ; name        trnbyte -- transmit byte of data over serial port 0
  255. ;
  256. ; synopsis    trnbyte(trndata);
  257. ;        int trnbyte;    ;data byte to send
  258. ;
  259. ; description    This routine sends a byte of data out serial port 0.
  260. ;
  261. _trnbyte     proc    near
  262.         push    bp        ;save BP
  263.         mov    bp,sp        ;point to passed parms
  264. trn_byte_loop:    inport    mdmsta        ;get status byte
  265.         and    al,20h        ;transmit buffer empty ?
  266.         jz    trn_byte_loop    ;loop if not
  267. if check_cts
  268.         inport    mdmmsr        ;get modem status reg.
  269.         and    al,10h        ;look at cts.
  270.         jz    trn_byte_loop    ;loop until ready.
  271. endif
  272.         mov    al,[bp+4]    ;get character to output
  273.         outport    mdmdat        ;send character
  274.  
  275.         pop    bp        ;restore callers BP
  276.         ret            ;all done so exit
  277. _trnbyte     endp
  278.  
  279.  
  280. ;
  281. ; name        rcvbyte -- receive byte from serial port 0
  282. ;
  283. ; synopsis    rcvbyte();
  284. ;
  285. ; description    This routine attempts to return a byte of data from
  286. ;        serial channel 0. If no data is available it returns
  287. ;        0ffffh else it returns the data with error status in
  288. ;        the high byte
  289. ;
  290. _rcvbyte     proc    near
  291.         mov    bx,rcvbuffout    ;is buffer empty
  292.         cmp    bx,rcvbuffin
  293.         mov    ax,0ffffh    ;load false return
  294.         je    short rcvend    ;if so go try leave
  295.         mov    ax,[bx]     ;get return byte
  296.         inc    bx        ;update pointer
  297.         inc    bx
  298.         cmp    bx,offset ds:rcv_buff_end
  299.         jl    rcvoutsav
  300.         mov    bx,offset ds:rcv_buff
  301. rcvoutsav:    mov    rcvbuffout,bx
  302.  
  303. rcvend:     ret            ;all done so exit
  304. _rcvbyte     endp
  305.  
  306. _rcvint        proc    far
  307.         push    ds        ;save present data seg
  308.         mov    ds,dsseg    ;set to C data segment
  309.         mov    ssseg,ss    ;save interrupted stack
  310.         mov    spptr,sp
  311.         mov    ss,dsseg    ;point to local stack
  312.         mov    sp,offset ds:intstk
  313.         push    ax        ;save everything
  314.         push    bx        ;
  315.         push    dx        ;
  316.         inport    mdmdat        ;get received char
  317.         mov    bl,al        ;save char
  318.         inport    mdmsta        ;get status
  319.         and    al,0eh        ;save only framing, and overrun error
  320.         mov    ah,al        ;put status into high byte
  321.         mov    al,bl        ;get char back
  322.         mov    bx,rcvbuffin    ;is buffer full
  323.         inc    bx
  324.         inc    bx
  325.         cmp    bx,offset ds:rcv_buff_end
  326.         jl    rcvint1
  327.         mov    bx,offset ds:rcv_buff
  328. rcvint1:    cmp    bx,rcvbuffout
  329.         je    short rcvintdn    ;if so leave
  330.         mov    bx,rcvbuffin
  331.         mov    [bx],ax     ;else save char and error status
  332.         inc    bx        ;update pointer
  333.         inc    bx
  334.         cmp    bx,offset ds:rcv_buff_end
  335.         jl    rcvint2
  336.         mov    bx,offset ds:rcv_buff
  337. rcvint2:    mov    rcvbuffin,bx
  338.  
  339. rcvintdn:
  340.         mov    ax,com_port    ;check which COM port
  341.         cmp    ax,0        ;COM1?
  342.         jnz    rcv_com2    ;no
  343.  
  344.         MOV    AL,60h+int_level1 ;specific EOI, level 1
  345.         jmp    short rcv_int_clr
  346.  
  347. rcv_com2:    MOV    AL,60h+int_level2 ;specific EOI, level 1
  348.  
  349. rcv_int_clr:    outbyte    i8259_ctrl    ;send specific EOI to 8259
  350. rcv_int_dn:    pop    dx        ;restore everything
  351.         pop    bx        ;
  352.         pop    ax        ;
  353.         mov    ss,ssseg    ;restore interrupted stack
  354.         mov    sp,spptr
  355.         pop    ds        ;restore data seg
  356.         iret            ;and leave
  357. _rcvint        endp
  358.  
  359. ;
  360. ; name        timercv -- receive with time out
  361. ;
  362. ; synopsis    timercv(timeout);
  363. ;        int timeout;    ;time out in seconds
  364. ;
  365. ; description    This routine tries to receive a char within a given
  366. ;        time. If a char becomes available it is returned.
  367. ;        Else if passed time elapses it returns -1 as an error.
  368. ;
  369. _timercv     proc    near
  370.         push    bp        ;save BP
  371.         mov    bp,sp        ;point to passed parms
  372.         sub    sp,4        ;make local storage
  373.         mov    ax,[bp+4]    ;get time to wait
  374.         mov    cx,182        ;find time in ticks
  375.         mul    cx
  376.         mov    cx,10
  377.         div    cx
  378.         mov    [bp-4],ax    ;save it
  379.         xor    ax,ax        ;find out current time in ticks
  380.         int    1ah
  381.         add    [bp-4],dx    ;make it ending time
  382.         adc    cx,0
  383.         mov    [bp-2],cx    ;and save it
  384.  
  385. timrlp:     call    _rcvbyte     ;is there a character ready
  386.         cmp    ax,0ffffh
  387.         jne    timrend     ;leave if so
  388.  
  389.         xor    ax,ax        ;else get new time
  390.         int    1ah
  391.         sub    dx,[bp-4]    ;timed out yet
  392.         sbb    cx,[bp-2]
  393.         jl    timrlp        ;if not go back and check again
  394.  
  395.         mov    ax,0ffffh    ;else error out
  396. timrend:    add    sp,4        ;deallocate local storage
  397.  
  398.         pop    bp        ;restore callers BP
  399.         ret            ;all done so exit
  400. _timercv     endp
  401.  
  402. ;
  403. ; name        purgercv -- purge receiver
  404. ;
  405. ; synopsis    purgercv();
  406. ;
  407. ; description    This routine keeps requesting receive characters
  408. ;        until the timercv times out for one second.
  409. ;
  410. _purgercv    proc    near
  411.         mov    ax,1        ;time out of one second
  412.         push    ax        ;
  413. purgelp:    call    _timercv     ;see if there are any chars
  414.         cmp    ax,0ffffh    ;did it time out
  415.         jne    purgelp     ;try again if not
  416.         pop    bx        ;clean stack
  417.         ret            ;done leave
  418. _purgercv    endp
  419.  
  420. ;
  421. ; name        serldone -- disables interrupts from serial port 0
  422. ;
  423. ; synopsis    serldone();
  424. ;
  425. ; description    This routine turns off interrupts from serial port 0
  426. ;        and restores the interrupt vectors to there default valuse
  427. ;
  428. _serldone    proc    near
  429.         push    bp        ;save BP
  430.         mov    bp,sp        ;point to passed parms
  431.  
  432.         call    _dtr_off    ;disable the port
  433.  
  434.         inbyte    i8259_mask    ;mask out interrupts from serial port
  435.  
  436.         push    ax        ;save it
  437.         mov    ax,com_port    ; check the port
  438.         cmp    ax,0        ;see if COM1
  439.         jnz    serd_mask2    ;must be COM2
  440.  
  441.         pop    ax        ;restore AX
  442.         or    al,int_mask1    ;disable interrupts for COM1
  443.         jmp    short serd_clrmask
  444.  
  445. serd_mask2:    pop    ax        ;restore AX
  446.         or    al,int_mask2    ;disable interrupts for COM2
  447.  
  448. serd_clrmask:    out    dx,al        ;restore new mask
  449.         pop    bp        ;restore callers BP
  450.         ret            ;all done so exit
  451. _serldone    endp
  452.  
  453. ;
  454. ; name        dtr_on -- turn on DTR handshaking line on RS-233 port
  455. ;
  456. ; synopsis    dtr_on();
  457. ;
  458. _dtr_on        proc    near
  459.          mov    al,linmod    ;clear DLAB bit and set line mode
  460.         outport    mdmlin        ;
  461.         inport    mdmmdm        ;get current setup
  462.         or    al,DTR_BIT    ;turn DTR on
  463.         outport    mdmmdm        ;to modem control register
  464.         ret
  465. _dtr_on        endp
  466.  
  467. ;
  468. ; name        dtr_off -- turn on DTR handshaking line off RS-233 port
  469. ;
  470. ; synopsis    dtr_off();
  471. ;
  472. _dtr_off    proc    near
  473.         mov    al,linmod    ;clear DLAB bit and set line mode
  474.         outport    mdmlin        ;
  475.         inport    mdmmdm        ;get current setup
  476.         and    al,not DTR_BIT    ;DTR off
  477.         outport    mdmmdm        ;to modem control register
  478.         ret
  479. _dtr_off    endp
  480.  
  481. ;
  482. ; name        rts_on -- turn on RTS handshaking line on RS-233 port
  483. ;
  484. ; synopsis    rts_on();
  485. ;
  486.  
  487. rts_on:     mov    al,linmod    ;clear DLAB bit and set line mode
  488.         outport    mdmlin        ;
  489.         inport    mdmmdm        ;get current setup
  490.         or    al,RTS_BIT    ;turn RTS on
  491.         outport    mdmmdm        ;to modem control register
  492.         ret
  493. ;
  494. ; name        rts_off -- turn on RTS handshaking line off RS-233 port
  495. ;
  496. ; synopsis    rts_off();
  497. ;
  498.  
  499. rts_off:    mov    al,linmod    ;clear DLAB bit and set line mode
  500.         outport    mdmlin        ;
  501.         inport    mdmmdm        ;get current setup
  502.         and    al,not RTS_BIT    ;RTS off
  503.         outport    mdmmdm        ;to modem control register
  504.         ret
  505.  
  506. ;
  507. ;    A routine to output a byte in al, to the port @ port_base, offset
  508. ;    by the value in dx
  509. ;
  510. out_byte:    push    ax        ;save the byte to send
  511.         mov    ax,port_base    ;get the base address
  512.         add    ax,dx        ;add the OFFSET
  513.         mov    dx,ax        ;set DX to point at port address
  514.         pop    ax        ;restore AX
  515.         out    dx,al        ;output 8 bit value
  516.         ret
  517.  
  518. _TEXT    ENDS
  519.     end
  520.